package com.hl.toolkit.server.util;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Locale;


public class ImageUtils {
	public static final int IMAGE_UNKNOWN = -1;
	public static final int IMAGE_JPEG = 0;
	public static final int IMAGE_PNG = 1;
	public static final int IMAGE_GIF = 2;

	public static BufferedImage resizeImage(String imgName, int type, int maxWidth, int maxHeight) {
		try {
			return resizeImage(ImageIO.read(new File(imgName)), type, maxWidth, maxHeight);
		} catch (Exception e) {
			e.getMessage();
		}
		return null;
	}

	public static BufferedImage resizeImage(BufferedImage image, int type, int maxWidth, int maxHeight) {
		Dimension largestDimension = new Dimension(maxWidth, maxHeight);

		int imageWidth = image.getWidth(null);
		int imageHeight = image.getHeight(null);

		float aspectRatio = imageWidth / imageHeight;

		if ((imageWidth > maxWidth) || (imageHeight > maxHeight)) {
			if (largestDimension.width / largestDimension.height > aspectRatio) {
				largestDimension.width = ((int) Math.ceil(largestDimension.height * aspectRatio));
			} else {
				largestDimension.height = ((int) Math.ceil(largestDimension.width / aspectRatio));
			}

			imageWidth = largestDimension.width;
			imageHeight = largestDimension.height;
		}

		return createHeadlessSmoothBufferedImage(image, type, imageWidth, imageHeight);
	}

	public static boolean saveImage(BufferedImage image, String toFileName, int type) {
		try {
			return ImageIO.write(image, type == 0 ? "jpg" : "png", new File(toFileName));
		} catch (IOException e) {
			e.getMessage();
		}
		return false;
	}

	public static void saveCompressedImage(BufferedImage image, String toFileName, int type) {
		try {
			if (type == 1) {
				throw new UnsupportedOperationException("PNG compression not implemented");
			}

			Iterator iter = ImageIO.getImageWritersByFormatName("jpg");

			ImageWriter writer = (ImageWriter) iter.next();

			ImageOutputStream ios = ImageIO.createImageOutputStream(new File(toFileName));
			writer.setOutput(ios);

			ImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault());

			iwparam.setCompressionMode(2);
			iwparam.setCompressionQuality(0.7F);

			writer.write(null, new IIOImage(image, null, null), iwparam);

			ios.flush();
			writer.dispose();
			ios.close();
		} catch (IOException e) {
			e.getMessage();
		}
	}

	public static BufferedImage createHeadlessBufferedImage(BufferedImage image, int type, int width, int height) {
		if ((type == 1) && (hasAlpha(image))) {
			type = 2;
		} else {
			type = 1;
		}

		BufferedImage bi = new BufferedImage(width, height, type);

		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				bi.setRGB(x, y, image.getRGB(x * image.getWidth() / width, y * image.getHeight() / height));
			}
		}

		return bi;
	}

	public static BufferedImage createHeadlessSmoothBufferedImage(BufferedImage source, int type, int width,
			int height) {
		if ((type == 1) && (hasAlpha(source))) {
			type = 2;
		} else {
			type = 1;
		}

		BufferedImage dest = new BufferedImage(width, height, type);

		double scalex = width / source.getWidth();
		double scaley = height / source.getHeight();

		for (int y = 0; y < height; y++) {
			int sourcey = y * source.getHeight() / dest.getHeight();
			double ydiff = scale(y, scaley) - sourcey;

			for (int x = 0; x < width; x++) {
				int sourcex = x * source.getWidth() / dest.getWidth();
				double xdiff = scale(x, scalex) - sourcex;

				int x1 = Math.min(source.getWidth() - 1, sourcex + 1);
				int y1 = Math.min(source.getHeight() - 1, sourcey + 1);

				int rgb1 = getRGBInterpolation(source.getRGB(sourcex, sourcey), source.getRGB(x1, sourcey), xdiff);
				int rgb2 = getRGBInterpolation(source.getRGB(sourcex, y1), source.getRGB(x1, y1), xdiff);

				int rgb = getRGBInterpolation(rgb1, rgb2, ydiff);

				dest.setRGB(x, y, rgb);
			}
		}

		return dest;
	}

	private static double scale(int point, double scale) {
		return point / scale;
	}

	private static int getRGBInterpolation(int value1, int value2, double distance) {
		int alpha1 = (value1 & 0xFF000000) >>> 24;
		int red1 = (value1 & 0xFF0000) >> 16;
		int green1 = (value1 & 0xFF00) >> 8;
		int blue1 = value1 & 0xFF;

		int alpha2 = (value2 & 0xFF000000) >>> 24;
		int red2 = (value2 & 0xFF0000) >> 16;
		int green2 = (value2 & 0xFF00) >> 8;
		int blue2 = value2 & 0xFF;

		int rgb = (int) (alpha1 * (1.0D - distance) + alpha2 * distance) << 24
				| (int) (red1 * (1.0D - distance) + red2 * distance) << 16
				| (int) (green1 * (1.0D - distance) + green2 * distance) << 8
				| (int) (blue1 * (1.0D - distance) + blue2 * distance);

		return rgb;
	}

	public static boolean hasAlpha(Image image) {
		try {
			PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
			pg.grabPixels();

			return pg.getColorModel().hasAlpha();
		} catch (InterruptedException e) {
		}
		return false;
	}
	
	

}